/**
 * ILP (InfluxDB Line Protocol) Client Example
 *
 * Demonstrates:
 * 1. Using ILP/HTTP transport instead of gRPC
 * 2. GZIP compression for bandwidth optimization
 * 3. Bearer Token / Basic Auth over HTTP
 * 4. Batch writes with ILP format
 * 5. Raw ILP string writes
 *
 * Usage:
 *   ./ilp_example [endpoint]
 *
 * Example:
 *   ./ilp_example 127.0.0.1:9091
 *   ./ilp_example localhost:9091
 */

#include "kwdb/ilp_client.h"
#include "kwdb/point.h"
#include <iostream>
#include <chrono>
#include <thread>
#include <cstdlib>

using namespace kwdb;

void test_single_write() {
    std::cout << "\n=== Test 1: Single Point Write (ILP) ===" << std::endl;

    IngestConfig config;
    config.ingest_endpoint = "127.0.0.1:9091";
    config.timeout_ms = 5000;

    IlpClient client(config);

    Point point("ilp_test");
    point.add_tag("host", "server1");
    point.add_tag("region", "us-west");
    point.add_field("cpu_usage", 45.6);
    point.add_field("memory_usage", 78.2);
    point.timestamp_now();

    Status status = client.write(point);

    if (status.ok()) {
        std::cout << "✓ Single point write succeeded" << std::endl;

        // Show the ILP format
        std::cout << "  ILP format: " << point_to_ilp(point) << std::endl;
    } else {
        std::cerr << "✗ Write failed: " << status.message << std::endl;
    }
}

void test_batch_write() {
    std::cout << "\n=== Test 2: Batch Write (ILP) ===" << std::endl;

    IngestConfig config;
    config.ingest_endpoint = "127.0.0.1:9091";
    config.timeout_ms = 5000;

    IlpClient client(config);

    std::vector<Point> points;
    for (int i = 0; i < 5; i++) {
        Point point("batch_metrics");
        point.add_tag("host", "server" + std::to_string(i));
        point.add_tag("datacenter", "dc1");
        point.add_field("value", i * 10.0);
        point.add_field("count", i * 100.0);
        point.timestamp_now();
        points.push_back(point);
    }

    Status status = client.batch_write(points);

    if (status.ok()) {
        std::cout << "✓ Batch write of " << points.size() << " points succeeded" << std::endl;
    } else {
        std::cerr << "✗ Batch write failed: " << status.message << std::endl;
    }
}

void test_gzip_compression() {
    std::cout << "\n=== Test 3: GZIP Compression ===" << std::endl;

    IngestConfig config;
    config.ingest_endpoint = "127.0.0.1:9091";
    config.security.gzip = true;  // Enable GZIP

    IlpClient client(config);

    // Create larger batch to benefit from compression
    std::vector<Point> points;
    for (int i = 0; i < 100; i++) {
        Point point("compression_test");
        point.add_tag("host", "server" + std::to_string(i % 10));
        point.add_tag("app", "myapp");
        point.add_tag("env", "production");
        point.add_field("cpu", 50.0 + (i % 50));
        point.add_field("memory", 60.0 + (i % 40));
        point.add_field("disk", 70.0 + (i % 30));
        point.add_field("network", 80.0 + (i % 20));
        point.timestamp_now();
        points.push_back(point);
    }

    Status status = client.batch_write(points);

    if (status.ok()) {
        std::cout << "✓ GZIP compressed write of " << points.size() << " points succeeded" << std::endl;

        // Calculate uncompressed size
        std::string ilp_data = points_to_ilp(points);
        std::cout << "  Uncompressed size: " << ilp_data.size() << " bytes" << std::endl;
        std::cout << "  (Compression happens internally)" << std::endl;
    } else {
        std::cerr << "✗ GZIP write failed: " << status.message << std::endl;
    }
}

void test_authentication() {
    std::cout << "\n=== Test 4: Authentication ===" << std::endl;

    // Test Bearer Token
    {
        IngestConfig config;
        config.ingest_endpoint = "127.0.0.1:9091";
        config.security.auth_token = "test-token-12345";

        std::cout << "Testing Bearer Token authentication..." << std::endl;

        IlpClient client(config);

        Point point("auth_test");
        point.add_field("authenticated", 1.0);
        point.timestamp_now();

        Status status = client.write(point);

        if (status.ok()) {
            std::cout << "✓ Bearer token auth succeeded (or server doesn't require auth)" << std::endl;
        } else {
            std::cout << "ℹ Auth failed: " << status.message << std::endl;
            std::cout << "  (Expected if server requires different credentials)" << std::endl;
        }
    }

    // Test Basic Auth
    {
        IngestConfig config;
        config.ingest_endpoint = "127.0.0.1:9091";
        config.security.username = "admin";
        config.security.password = "password";

        std::cout << "Testing Basic authentication..." << std::endl;

        IlpClient client(config);

        Point point("auth_test");
        point.add_field("authenticated", 2.0);
        point.timestamp_now();

        Status status = client.write(point);

        if (status.ok()) {
            std::cout << "✓ Basic auth succeeded (or server doesn't require auth)" << std::endl;
        } else {
            std::cout << "ℹ Auth failed: " << status.message << std::endl;
            std::cout << "  (Expected if server requires different credentials)" << std::endl;
        }
    }
}

void test_raw_ilp() {
    std::cout << "\n=== Test 5: Raw ILP String Write ===" << std::endl;

    IngestConfig config;
    config.ingest_endpoint = "127.0.0.1:9091";

    IlpClient client(config);

    // Manually construct ILP format string
    std::string ilp_line = "raw_measurement,host=server1,region=us-west cpu=45.6,memory=78.2 ";

    // Add timestamp
    auto now = std::chrono::system_clock::now();
    auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
        now.time_since_epoch()
    ).count();
    ilp_line += std::to_string(ns);

    std::cout << "Raw ILP: " << ilp_line << std::endl;

    Status status = client.write_raw(ilp_line);

    if (status.ok()) {
        std::cout << "✓ Raw ILP write succeeded" << std::endl;
    } else {
        std::cerr << "✗ Raw write failed: " << status.message << std::endl;
    }
}

void test_performance() {
    std::cout << "\n=== Test 6: Performance Test ===" << std::endl;

    IngestConfig config;
    config.ingest_endpoint = "127.0.0.1:9091";
    config.security.gzip = true;

    IlpClient client(config);

    const int num_batches = 10;
    const int batch_size = 100;

    auto start = std::chrono::high_resolution_clock::now();

    for (int b = 0; b < num_batches; b++) {
        std::vector<Point> points;

        for (int i = 0; i < batch_size; i++) {
            Point point("perf_test");
            point.add_tag("batch", std::to_string(b));
            point.add_tag("index", std::to_string(i));
            point.add_field("value", b * batch_size + i);
            point.timestamp_now();
            points.push_back(point);
        }

        Status status = client.batch_write(points);
        if (!status.ok()) {
            std::cerr << "✗ Batch " << b << " failed: " << status.message << std::endl;
            break;
        }
    }

    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);

    int total_points = num_batches * batch_size;
    double qps = (total_points * 1000.0) / duration.count();

    std::cout << "✓ Performance test completed" << std::endl;
    std::cout << "  Total points: " << total_points << std::endl;
    std::cout << "  Duration: " << duration.count() << " ms" << std::endl;
    std::cout << "  QPS: " << qps << " points/sec" << std::endl;
}

int main(int argc, char** argv) {
    std::cout << "============================================" << std::endl;
    std::cout << "  KWDB ILP Client Example" << std::endl;
    std::cout << "============================================" << std::endl;

    // Override endpoint if provided
    if (argc > 1) {
        std::cout << "Using custom endpoint: " << argv[1] << std::endl;
        // Would set globally, but for demo we use default
    }

    try {
        test_single_write();
        test_batch_write();
        test_gzip_compression();
        test_authentication();
        test_raw_ilp();
        test_performance();

        std::cout << "\n============================================" << std::endl;
        std::cout << "  All ILP Tests Completed" << std::endl;
        std::cout << "============================================" << std::endl;

    } catch (const std::exception& e) {
        std::cerr << "\n✗ Test failed with exception: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}